package com.heima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.model.search.vos.SearchArticleRetVo;
import com.heima.model.search.vos.SearchArticleVo;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.search.service.ArticleSearchService;
import com.heima.search.service.UserSearchHistoryService;
import com.heima.utils.thread.WmThreadLocalUtil;
import io.micrometer.core.instrument.search.Search;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {

    @Autowired
    @Qualifier("client")
    RestHighLevelClient restHighLevelClient;

    @Autowired
    UserSearchHistoryService userSearchHistoryService;

    @Override
    public ResponseResult search(UserSearchDto dto) {
        log.info("搜索  线程名词:{}", Thread.currentThread().getName());
        //1.校验
        if(dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        if(dto.getPageNum()<1){
            dto.setPageNum(1);
        }
        if(dto.getPageSize()<1 || dto.getPageSize()>100){
            dto.setPageSize(10);
        }

        //异步记录当前用户  的该搜索关键字
        WmUser user = WmThreadLocalUtil.getUser();
        if(user!=null  && dto.getFromIndex()==0 ){//用户登陆 且 pageNum为1 才需要记录该关键字    异步
            //需要记录该关键字
            userSearchHistoryService.insert(dto, user.getId());
        }


        //2.创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("app_info_article114");

        //3.设置dsl参数
        SearchSourceBuilder ssb = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        if(StringUtils.isNotBlank(dto.getSearchWords())){
            //搜索 title和content字段   或的关系   可以给title或者 content设置权重
            QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(dto.getSearchWords())
                    .field("title",10)//给title字段设置10倍权重
                    .field("content")
                    .defaultOperator(Operator.OR);
            boolQueryBuilder.must(queryStringQueryBuilder);
        }
        if(dto.getMinBehotTime()!=null){
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime().getTime());
            boolQueryBuilder.filter(rangeQueryBuilder);//filter 不计算得分  性能高
        }

        //dto.getPageNum()  第几页
        ssb.from(dto.getFromIndex());//分页起始下标
        ssb.size(dto.getPageSize());//搜索几条
        ssb.query(boolQueryBuilder);
        ssb.sort("publishTime", SortOrder.DESC);//按照文章发布时间倒序;
        //设置高亮

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");//设置高亮字段
        highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>");//设置高亮前缀
        highlightBuilder.postTags("</font>");//设置高亮后缀
        highlightBuilder.requireFieldMatch(false);//如果搜索字段和高亮字段 不匹配 设置该项为false

        ssb.highlighter(highlightBuilder);

        searchRequest.source(ssb);
//        searchRequest.source().query(xxxxxx);


        //4.发起请求
        try {
            SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

            //5.解析响应
            List<SearchArticleRetVo> list = new ArrayList<>();
            SearchHits searchHits = response.getHits();
            SearchHit[] searchHitsHits = searchHits.getHits();
            for (SearchHit searchHitsHit : searchHitsHits) {
                String sourceAsString = searchHitsHit.getSourceAsString();
                SearchArticleRetVo searchArticleRetVo = JSON.parseObject(sourceAsString, SearchArticleRetVo.class);

                /*HighlightField highlightField1 = searchHitsHit.getHighlightFields().get("title");


                // 保留原始标题
                apArticle.put("h_title", apArticle.get("title"));



                if(highlightField1!=null){
                    // 获取高亮结果集
                    Text[] titles = highlightField1.getFragments();
                    //["<>传智</>","教育"]

                    String title = StringUtils.join(titles);
                    if (StringUtils.isNotBlank(title)) {
                        apArticle.put("h_title", title);
                    }
                }*/






                //取高亮
                Map<String, HighlightField> highlightFields = searchHitsHit.getHighlightFields();

                searchArticleRetVo.setH_title(searchArticleRetVo.getTitle());//将title值赋值给h_title

                if(highlightFields!=null && highlightFields.size()>0){
                    HighlightField highlightField = highlightFields.get("title");
                    if(highlightField!=null){
                        Text[] fragments = highlightField.getFragments();
                        if(fragments!=null && fragments.length>0){
                            String highlightTitle = StringUtils.join(fragments);
                            if(StringUtils.isNotBlank(highlightTitle)){
                                //将高亮的标题设置到h_title  覆盖
                                searchArticleRetVo.setH_title(highlightTitle);
                            }
                        }
                    }
                }
                list.add(searchArticleRetVo);
            }
            return ResponseResult.okResult(list);

        } catch (IOException e) {
            log.error("搜索es报错了", e);
        }
        return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR);
    }
}
